package com.zmn.oms.task.ins.impl;

import com.alibaba.fastjson.JSON;
import com.github.ltsopensource.core.domain.Job;
import com.zmn.biz.engineer.dubbo.interfaces.insorder.EngineerInsOrderModifyRemoteService;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.manager.lts.interfaces.task.TaskManager;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.manager.redis.RedisManager;
import com.zmn.oms.common.constant.InsConsts;
import com.zmn.oms.common.constant.RedisKeyConsts;
import com.zmn.oms.manager.utils.TaskConsts;
import com.zmn.oms.model.dto.ins.InsOrderMasterCpicDTO;
import com.zmn.oms.model.entity.ins.InsOrder;
import com.zmn.oms.model.entity.ins.InsOrderMasterCpic;
import com.zmn.oms.model.entity.ins.InsOrderMasterSync;
import com.zmn.oms.model.entity.ins.InsOrderSync;
import com.zmn.oms.services.interfaces.ins.InsOrderMasterCpicService;
import com.zmn.oms.services.interfaces.ins.InsOrderMasterSyncService;
import com.zmn.oms.services.interfaces.ins.InsOrderSyncService;
import com.zmn.oms.task.ins.CpicInsSyncInvoker;
import com.zmn.oms.task.ins.InsOrderSyncBService;
import com.zmn.oms.zmn.business.interfaces.ins.InsCpicInsureBService;
import com.zmn.oms.zmn.business.interfaces.ins.InsOrderBService;
import io.shardingsphere.api.HintManager;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 类描述：
 *
 * @author lhl
 * @date 2020/06/17 11:05
 */
@Slf4j
@Service
public class InsOrderSyncBServiceImpl implements InsOrderSyncBService {
    // region 私有常量
    private static final String LOG_HEAD = "按单保险同步";
    /**
     * 判定超时未同步的时间间隔，即超过该时间间隔仍未同步的判定未同步超时
     */
    private static final int SYNC_TIMEOUT_LIMIT_MINUTE = 30;
    /**
     * 一次查出需要同步的数据的条数
     */
    private static final int LIST_NOSYNCED_ROWS = 200;
    /**
     * 一次查出需要同步的数据的条数
     */
    private static final int LIST_INSURE_ROWS = 200;
    // endregion

    // region 依赖
    //@Reference(version = com.zmn.base.engineer.common.constants.DubboConsts.INTERFACE_VERSION, check = false)
    //protected EngineerInsOrderPlatModifyRemoteService engineerInsOrderPlatModifyRemoteService;

    @Reference(version = com.zmn.base.engineer.common.constants.DubboConsts.INTERFACE_VERSION, check = false)
    protected EngineerInsOrderModifyRemoteService engineerInsOrderModifyRemoteService;

    @Autowired
    protected RedisManager redisManager;
    @Autowired
    protected TaskManager taskManager;
    @Autowired
    protected ZmnMQSender zmnMQSender;
    @Autowired
    private InsOrderBService insOrderBService;
    @Autowired
    private InsOrderSyncService insOrderSyncService;
    @Autowired
    private InsCpicInsureBService insCpicInsureBService;
    @Autowired
    private InsOrderMasterSyncService insOrderMasterSyncService;
    @Autowired
    private InsOrderMasterCpicService insOrderMasterCpicService;
    @Resource(name="insOrderSyncExecutor")
    private ThreadPoolTaskExecutor insOrderSyncExecutor;
    // endregion

    /**
     * 执行同步逻辑
     */
    @Override
    public void execSycn() {

        // 1. 同步师傅保险给ERP
        try {
            // 同步师傅保单数据
            insOrderSyncExecutor.execute(new SyncMasterInsurance2ErpTask(
                    insOrderMasterCpicService, insOrderBService, zmnMQSender
            ));
            // 同步完成订单的师傅
            insOrderSyncExecutor.execute(new SyncOrderMainMaster2ErpTask(
                    insOrderMasterSyncService, insOrderMasterCpicService, zmnMQSender
            ));
        } catch (Exception e) {
            log.error(String.format("【%s】同步师傅保险给ERP失败：%s", LOG_HEAD, e.getMessage()), e);
        }

        // 查出需要同步的数据
        List<InsOrderSync> zmnInsOrderSyncs = insOrderSyncService.listZmnNoSynced(LIST_NOSYNCED_ROWS);
        List<InsOrderSync> yeyxInsOrderSyncs = insOrderSyncService.listYeyxNoSynced(LIST_NOSYNCED_ROWS);

        // 2. 处理超时未同步提示
        try {
            procNotifyTips(zmnInsOrderSyncs, yeyxInsOrderSyncs);
        } catch (Exception e) {
            log.error(String.format("【%s】发送提示失败：%s", LOG_HEAD, e.getMessage()), e);
        }

        // 3. 给保险公司同步数据
        try {
            if (!CollectionUtils.isEmpty(zmnInsOrderSyncs)) {
                SyncInsOrderTask zmnTask = new SyncInsOrderTask(insOrderSyncService, zmnInsOrderSyncs,
                        redisManager, GlobalConsts.PLAT_MARK_ZMN);
                insOrderSyncExecutor.execute(zmnTask);
            }
            if (!CollectionUtils.isEmpty(yeyxInsOrderSyncs)) {
                SyncInsOrderTask yeyxTask = new SyncInsOrderTask(insOrderSyncService, yeyxInsOrderSyncs,
                        redisManager, GlobalConsts.PLAT_MARK_YEYX);
                insOrderSyncExecutor.execute(yeyxTask);
            }
        } catch (Exception e) {
            log.error(String.format("【%s】给保险公司同步数据失败：%s", LOG_HEAD, e.getMessage()), e);
        }

        // 4. 主动查询超时未回复的保险数据是否已出单
        try {
            List<InsOrderMasterCpic> insOrderMasterCpics = insOrderMasterCpicService.listFormStatusPending(LIST_INSURE_ROWS);
            if (!CollectionUtils.isEmpty(zmnInsOrderSyncs)) {
                QueryInsOrderMasterCpicTask zmnTask = new QueryInsOrderMasterCpicTask(insOrderMasterCpicService,
                        insCpicInsureBService, insOrderMasterCpics, redisManager, GlobalConsts.PLAT_MARK_ZMN);
                insOrderSyncExecutor.execute(zmnTask);
            }
        } catch (Exception e) {
            log.error(String.format("【%s】主动查询超时未回复的保险数据失败：%s", LOG_HEAD, e.getMessage()), e);
        }

        // 5. 给师傅买保险
        try {
            List<InsOrderMasterCpic> insOrderMasterCpics = insOrderMasterCpicService.listNoSynced(LIST_INSURE_ROWS);
            if (!CollectionUtils.isEmpty(zmnInsOrderSyncs)) {
                SyncInsOrderMasterCpicTask zmnTask = new SyncInsOrderMasterCpicTask(insOrderMasterCpicService,
                        insOrderMasterCpics, redisManager, GlobalConsts.PLAT_MARK_ZMN);
                insOrderSyncExecutor.execute(zmnTask);
            }
        } catch (Exception e) {
            log.error(String.format("【%s】同步买保险的师傅数据失败：%s", LOG_HEAD, e.getMessage()), e);
        }

        // 6. 重传买保险失败的师傅数据
        try {
            List<InsOrderMasterCpic> insOrderMasterCpics = insOrderMasterCpicService.listFormStatusFail(LIST_INSURE_ROWS);
            if (!CollectionUtils.isEmpty(zmnInsOrderSyncs)) {
                ReSyncInsOrderMasterCpicTask zmnTask = new ReSyncInsOrderMasterCpicTask(insOrderMasterCpicService,
                        insOrderMasterCpics, redisManager, taskManager, GlobalConsts.PLAT_MARK_ZMN);
                insOrderSyncExecutor.execute(zmnTask);
            }
        } catch (Exception e) {
            log.error(String.format("【%s】重传买保险失败的师傅数据失败：%s", LOG_HEAD, e.getMessage()), e);
        }
    }

    /**
     * 检查二次同步保险信息是否出单
     * @param insMasterIds
     */
    @Override
    public void checkResyncResult(String insMasterIds) {
        List<Long> list = Optional.ofNullable(insMasterIds)
                .map(ids -> ids.split(","))
                .map(arr -> {
                    List<Long> idList = new ArrayList(arr.length);
                    for (String id : arr) {
                        idList.add(Long.parseLong(id));
                    }
                    return idList;
                })
                .get();
        if (list == null || list.size() == 0) {
            return;
        }

        insCpicInsureBService.sendDingTalkMessageOnFailed(list);
    }

    // region 处理超时未同步提示
    /**
     * 处理超时未同步提示
     * @param zmnInsOrderSyncs
     * @param yeyxInsOrderSyncs
     */
    private void procNotifyTips(List<InsOrderSync> zmnInsOrderSyncs, List<InsOrderSync> yeyxInsOrderSyncs) {
        // 触发显示或撤销显示“有超时未同步的数据”提示
        boolean syncTimeout = false;

        // 时间间隔，单位毫秒，便于计算
        long timeLimit = SYNC_TIMEOUT_LIMIT_MINUTE * 60 * 1000;
        long currentTime = System.currentTimeMillis();

        // 查看是否有同步超时的数据
        if (!CollectionUtils.isEmpty(zmnInsOrderSyncs)) {
            for (InsOrderSync item : zmnInsOrderSyncs) {
                long itemTimeLimit = currentTime - item.getCreatedOn().getTime();
                if (itemTimeLimit > timeLimit) {
                    syncTimeout = true;
                    break;
                }
            }
        }
        if (!syncTimeout && !CollectionUtils.isEmpty(yeyxInsOrderSyncs)) {
            for (InsOrderSync item : yeyxInsOrderSyncs) {
                long itemTimeLimit = currentTime - item.getCreatedOn().getTime();
                if (itemTimeLimit > timeLimit) {
                    syncTimeout = true;
                    break;
                }
            }
        }

        // 存在超时未同步数据时，且没有通知过有“未同步数据”提示时，发送提示通知
        if (syncTimeout) {
            if (!_isNotifiedTips()) {
                _doNotifyTips(true);
            }
        }
        // 不存在超时未同步数据时，且之前通知过有“未同步数据”提示时，发送撤销提示通知
        else {
            if (_isNotifiedTips()) {
                _doNotifyTips(false);
            }
        }
    }

    /**
     * 是否做了“存在超时未同步”的提示通知
     * @return
     */
    private boolean _isNotifiedTips() {
        String rdsTimeoutFlag = redisManager.get(RedisKeyConsts.INS_SYNC_TIMEOUT_FLAG);
        boolean isNotifyTips = StringUtil.isNotBlank(rdsTimeoutFlag) && "1".equals(rdsTimeoutFlag);
        return isNotifyTips;
    }

    /**
     * 发送通知提示
     * @param existTimeoutData true：表示发送“存在超时未同步”提示； false：表示发送“不存在超时未同步”提示；
     * @return
     */
    private void _doNotifyTips(boolean existTimeoutData) {
        try {
            if (existTimeoutData) {
                redisManager.set(RedisKeyConsts.INS_SYNC_TIMEOUT_FLAG, "1");

                // 发送“存在超时未同步”提示
                log.info("【{}】发送'存在超时未同步'提示通知-Request", LOG_HEAD);
                ResponseDTO<Boolean> booleanResponseDTO = engineerInsOrderModifyRemoteService.insOrderSyncAbnormalTag();
                log.info("【{}】发送'存在超时未同步'提示通知-Response: ResponseDTO=[{}]", LOG_HEAD,
                        JSON.toJSONString(booleanResponseDTO));
            }
            else {
                redisManager.del(RedisKeyConsts.INS_SYNC_TIMEOUT_FLAG);

                // 发送“不存在超时未同步”提示
                log.info("【{}】发送'存在超时未同步'取消通知-Request", LOG_HEAD);
                ResponseDTO<Boolean> booleanResponseDTO = engineerInsOrderModifyRemoteService.clearInsOrderSyncAbnormalTag();
                log.info("【{}】发送'存在超时未同步'取消通知-Response: ResponseDTO=[{}]", LOG_HEAD,
                        JSON.toJSONString(booleanResponseDTO));
            }
        } catch (Exception e) {
            log.error(String.format("【%s】发送提示失败：%s", LOG_HEAD, e.getMessage()), e);
        }
    }
    // endregion

    /**
     * 同步师傅保险数据给ERP任务
     */
    @Slf4j
    public static class SyncMasterInsurance2ErpTask implements Runnable {
        private static final String LOG_HEAD = "同步师傅保单号到ERP任务";
        private static final int MAX_ROW_NUM = 100;

        private InsOrderMasterCpicService insOrderMasterCpicService;
        private InsOrderBService insOrderBService;
        private ZmnMQSender zmnMQSender;

        /**
         * 构造器
         * @param insOrderMasterCpicService
         * @param insOrderBService
         * @param zmnMQSender
         */
        public SyncMasterInsurance2ErpTask(InsOrderMasterCpicService insOrderMasterCpicService,
                                           InsOrderBService insOrderBService,
                                           ZmnMQSender zmnMQSender) {
            this.insOrderMasterCpicService = insOrderMasterCpicService;
            this.insOrderBService = insOrderBService;
            this.zmnMQSender = zmnMQSender;
        }

        @Override
        public void run() {
            List<InsOrderMasterCpic> dbInsOrderMasterCpics = this.listErpNoSynced();
            if (CollectionUtils.isEmpty(dbInsOrderMasterCpics)) {
                return;
            }

            // 保存同步失败的数据的ID。用于本地库更新数据的同步状态
            List<Long> syncFailedInsMasterSyncIdList = new ArrayList<>(dbInsOrderMasterCpics.size());

            // 组织待同步的师傅保单数据
            DateFormat dateFormat = new SimpleDateFormat(DateUtil.FORMAT_DEFAULT);
            for (InsOrderMasterCpic item : dbInsOrderMasterCpics) {
                MasterInsurance masterInsurance = this.newMasterInsurance(item, dateFormat);
                if (masterInsurance == null || !sendMqMessage(masterInsurance)) {
                    // 记录未同步的数据ID
                    syncFailedInsMasterSyncIdList.add(item.getInsMasterId());
                }
            }

            // 将保单数据的在数据库标记为未同步
            if (!syncFailedInsMasterSyncIdList.isEmpty()) {
                insOrderMasterCpicService.updateErpSyncFailByKeys(syncFailedInsMasterSyncIdList);
            }
        }

        private List<InsOrderMasterCpic> listErpNoSynced() {
            try (HintManager hintManager = HintManager.getInstance()) {
                hintManager.setMasterRouteOnly();

                List<InsOrderMasterCpic> insOrderMasterCpics = insOrderMasterCpicService.listErpNoSynced(MAX_ROW_NUM);
                if (CollectionUtils.isEmpty(insOrderMasterCpics)) {
                    return insOrderMasterCpics;
                }

                {
                    /*
                        原有逻辑中，查出待同步数据后，需要发送至消息队列，再更新数据库的同步状态，
                        但发送消息队列需要的时间过长，造成更新数据库中的待同步状态延后，
                        这会导致在更新另一个线程读取到同样的待同步数据，最终造成同步两次相同的数据。

                        对于这个问题，决定采用提前更新状态的办法，规避掉发送消息队列造成的时间滞后，
                        即：查出待同步数据后，马上将其同步状态更新为“完成”，然后再向消息队列发送数据，
                        如果遇到发送消息队列失败的情况，再将状态改回到未同步状态即可
                        2021.09.06 by lhl
                     */

                    // 先将数据标记为同步完成，重复
                    List<Long> insMasterIds = insOrderMasterCpics.stream()
                            .map(InsOrderMasterCpic::getInsMasterId)
                            .collect(Collectors.toList());
                    insOrderMasterCpicService.updateErpSyncSuccessByKeys(insMasterIds);
                }
                /*
                    InsOrderMasterCpic对应的表（ins_order_master_cpic）中新增了字段，但之前的数据中新增字段没有值，
                    需要从表（ins_order）中查找对应的数据补全这些缺失的字段。 2021.07.29 by lhl
                    流程如下：
                        1. 找出数据不全的师傅保险信息，按订单号构建查找器，为补全数据做准备；
                        2. 为减少查表（ins_order）次数，收集所有保险订单号，为批量查询做准备；
                        3. 使用步骤2中收集的保险订单号一次查出所有待补充数据，再通过步骤1构建的查找器补全数据
                 */
                // 步骤1、2
                Map<Long, List<InsOrderMasterCpic>> missingErpDataObjectFilter = new HashMap<>(insOrderMasterCpics.size());
                List<Long> orderIds = new ArrayList<>(insOrderMasterCpics.size());
                for (InsOrderMasterCpic item : insOrderMasterCpics) {
                    if (item.getPlat() == null) {
                        Long orderId = item.getOrderId();
                        orderIds.add(orderId);

                        List<InsOrderMasterCpic> list = missingErpDataObjectFilter.get(orderId);
                        if (list == null) {
                            list = new ArrayList<>(10);
                            missingErpDataObjectFilter.put(orderId, list);
                        }
                        list.add(item);
                    }
                }
                // 步骤3
                if (!orderIds.isEmpty()) {
                    List<InsOrder> insOrders = insOrderBService.listInsOrderByOrderIds(orderIds);
                    for (InsOrder insOrder : insOrders) {
                        List<InsOrderMasterCpic> list = missingErpDataObjectFilter.get(insOrder.getOrderId());
                        if (list == null) {
                            continue;
                        }
                        for (InsOrderMasterCpic item : list) {
                            item.setPlat(insOrder.getPlat());
                            item.setCityId(insOrder.getCityId());
                            item.setCompanyId(insOrder.getCompanyId());
                            item.setCompanyName(insOrder.getCompanyName());
                            item.setManageCompanyId(insOrder.getManageCompanyId());
                            item.setManageCompanyName(insOrder.getManageCompanyName());
                            item.setServCategId(insOrder.getServCategId());
                            item.setCategOneId(insOrder.getCategOneId());
                            item.setCategId(insOrder.getCategId());
                            item.setProductId(insOrder.getProductId());
                            item.setCategTag(insOrder.getCategTag());
                        }
                    }
                }

                return insOrderMasterCpics;
            }
        }

        private MasterInsurance newMasterInsurance(InsOrderMasterCpic insOrderMasterCpic,
                                                   DateFormat dft) {
            try {
                MasterInsurance masterInsurance = new MasterInsurance();
                masterInsurance.setOrderId(insOrderMasterCpic.getOrderId());
                masterInsurance.setPlat(insOrderMasterCpic.getPlat());
                masterInsurance.setCityId(insOrderMasterCpic.getCityId());
                // 公司信息
                masterInsurance.setCompanyId(insOrderMasterCpic.getCompanyId());
                masterInsurance.setCompanyName(
                        StringUtil.isNotBlank(insOrderMasterCpic.getCompanyName())
                                ? insOrderMasterCpic.getCompanyName()
                                : "未知"
                );
                masterInsurance.setManageCompanyId(insOrderMasterCpic.getManageCompanyId());
                masterInsurance.setManageCompanyName(insOrderMasterCpic.getManageCompanyName());
                //masterInsurance.setCreater("system");
                // 补充师傅信息
                masterInsurance.setMasterId(insOrderMasterCpic.getMasterId());
                masterInsurance.setMasterName(insOrderMasterCpic.getMasterName());
                masterInsurance.setMasterMoblie(insOrderMasterCpic.getMasterPhone());
                // 补充产品信息
                masterInsurance.setServCategId(insOrderMasterCpic.getServCategId());
                masterInsurance.setCategOneId(insOrderMasterCpic.getCategOneId());
                masterInsurance.setCategId(insOrderMasterCpic.getCategId());
                masterInsurance.setProductId(insOrderMasterCpic.getProductId());
                // 保险信息
                masterInsurance.setInsuranceNo(insOrderMasterCpic.getInsureNo());
                masterInsurance.setInsStartTime(dft.parse(insOrderMasterCpic.getInsStartDate()));
                masterInsurance.setInsEndTime(dft.parse(insOrderMasterCpic.getInsEndDate()));
                // 保险计价分类
                switch (insOrderMasterCpic.getCategTag()) {
                    case InsConsts.CATEG_TAG_OTHER:
//                        masterInsurance.setTag(EngineerInsOrderConsts.CATEG_TAG_OTHER);
                        masterInsurance.setTag(0);
                        break;
                    case InsConsts.CATEG_TAG_AC_REPAIR:
//                        masterInsurance.setTag(EngineerInsOrderConsts.CATEG_TAG_AC_REPAIR);
                        masterInsurance.setTag(201);
                        break;
                    case InsConsts.CATEG_TAG_AC_INSTALL:
//                        masterInsurance.setTag(EngineerInsOrderConsts.CATEG_TAG_AC_INSTALL);
                        masterInsurance.setTag(301);
                        break;
                    case InsConsts.CATEG_TAG_SOLAR_HEATER_REPAIR:
//                        masterInsurance.setTag(EngineerInsOrderConsts.CATEG_TAG_SOLAR_HEATER_REPAIR);
                        masterInsurance.setTag(202);
                        break;
                    case InsConsts.CATEG_TAG_SOLAR_HEATER_INSTALL:
//                        masterInsurance.setTag(EngineerInsOrderConsts.CATEG_TAG_SOLAR_HEATER_INSTALL);
                        masterInsurance.setTag(302);
                        break;
                }
                return masterInsurance;
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            return null;
        }

        private boolean sendMqMessage(MasterInsurance masterInsurance) {
            try {
                String mqMsgKey = String.format("sync_insMaster_%s", StringUtil.getRandomStringAndNumber3(17));
                MasterInsuranceMessage message = new MasterInsuranceMessage();
                message.setMqMsgKey(mqMsgKey);
                message.setData(masterInsurance);
                String jsonContent = JSON.toJSONString(message);

                // 将师傅保单数据发送至消息队列
                zmnMQSender.send(
                        InsConsts.ZMN_TOPIC_ENGINEER,
                        InsConsts.MQ_TAG_MASTER_INSURANCE ,
                        mqMsgKey,
                        jsonContent
                );
                log.info("【{}】send to MQ: content=[{}]", LOG_HEAD, jsonContent);
                return true;
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                return false;
            }
        }

        @Data
        private class MasterInsuranceMessage {
            private String mqMsgKey;
            private MasterInsurance data;
        }

        @Data
        private class MasterInsurance {
            private Long orderId;
            private String insuranceNo;
            private Integer companyId;
            private String companyName;
            private Integer manageCompanyId;
            private String manageCompanyName;
            private Integer cityId;
            private String cityName;
            private Integer masterId;
            private String masterName;
            private String masterMoblie;
            private Integer servCategId;
            private Integer categOneId;
            private Integer categId;
            private Integer productId;
            private Date insStartTime;
            private Date insEndTime;
            private Integer plat;
            private Integer tag;
        }

    }

    /**
     * 同步完成订单师傅给ERP任务
     */
    @Slf4j
    public static class SyncOrderMainMaster2ErpTask implements Runnable {
        private static final String LOG_HEAD = "同步完成订单师傅给ERP任务";
        private static final int MAX_ROW_NUM = 100;

        private InsOrderMasterSyncService insOrderMasterSyncService;
        private InsOrderMasterCpicService insOrderMasterCpicService;
        private ZmnMQSender zmnMQSender;

        /**
         * 构造器
         * @param insOrderMasterSyncService
         * @param insOrderMasterCpicService
         * @param zmnMQSender
         */
        public SyncOrderMainMaster2ErpTask(InsOrderMasterSyncService insOrderMasterSyncService,
                                           InsOrderMasterCpicService insOrderMasterCpicService,
                                           ZmnMQSender zmnMQSender) {
            this.insOrderMasterSyncService = insOrderMasterSyncService;
            this.insOrderMasterCpicService = insOrderMasterCpicService;
            this.zmnMQSender = zmnMQSender;
        }

        @Override
        public void run() {
            List<InsOrderMasterSync> dbInsOrderMasterSyncs = insOrderMasterSyncService.listNoSynced(MAX_ROW_NUM);
            if (CollectionUtils.isEmpty(dbInsOrderMasterSyncs)) {
                return;
            }

            // 将状态置为同步中
            List<Long> allIds = dbInsOrderMasterSyncs.stream()
                    .map(InsOrderMasterSync::getInsMasterSyncId)
                    .collect(Collectors.toList());
            insOrderMasterSyncService.updateSyncPendingByKeys(allIds);

            // 保存同步成功的数据的ID。用于本地库更新数据的同步状态
            Map<Long, InsOrderMasterSync> insMasterSyncFilter = new HashMap<>(dbInsOrderMasterSyncs.size());
            List<OrderMainMaster> orderMainMasters = new ArrayList<>(dbInsOrderMasterSyncs.size());
            // 组织待同步的师傅保单数据
            for (InsOrderMasterSync item : dbInsOrderMasterSyncs) {
                insMasterSyncFilter.put(item.getOrderId(), item);
                orderMainMasters.add(this.newOrderMainMaster(item));
            }

            this.fillInsuranceNo(orderMainMasters);

            List<Long> successIdList = new ArrayList<>(orderMainMasters.size());
            List<Long> failIdList = new ArrayList<>(orderMainMasters.size());
            List<Long> unsyncList = new ArrayList<>(orderMainMasters.size());

            for (OrderMainMaster item : orderMainMasters) {
                // 没有保单号，记录为失败
                if (StringUtil.isBlank(item.insuranceNo)) {
                    failIdList.add(insMasterSyncFilter.get(item.orderId).getInsMasterSyncId());
                    continue;
                }

                if (this.sendMqMessage(item)) {
                    successIdList.add(insMasterSyncFilter.get(item.orderId).getInsMasterSyncId());
                }
                else {
                    // 发送消息失败的不做处理，以便重试
                    unsyncList.add(insMasterSyncFilter.get(item.orderId).getInsMasterSyncId());
                }
            }

            if (!unsyncList.isEmpty()) {
                try {
                    // 将保单数据的在数据库标记为未同步
                    insOrderMasterSyncService.updateUnSyncedByKeys(failIdList);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (!successIdList.isEmpty()) {
                try {
                    // 将保单数据的在数据库标记为已同步
                    insOrderMasterSyncService.updateSyncedSuccessByKeys(successIdList);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (!failIdList.isEmpty()) {
                try {
                    // 将保单数据的在数据库标记为数据不全，同步失败
                    insOrderMasterSyncService.updateSyncedFailByKeys(failIdList);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        }

        private OrderMainMaster newOrderMainMaster(InsOrderMasterSync insOrderMasterSync) {
            OrderMainMaster orderMainMaster = new OrderMainMaster();
            orderMainMaster.setOrderId(insOrderMasterSync.getOrderId());
            orderMainMaster.setPlat(insOrderMasterSync.getPlat());
            orderMainMaster.setMasterId(insOrderMasterSync.getMasterId());
            return orderMainMaster;
        }

        private void fillInsuranceNo(List<OrderMainMaster> orderMainMasters) {
            if (orderMainMasters.isEmpty()) {
                return;
            }
            List<Long> orderIds = new ArrayList<>(orderMainMasters.size());
            Map<Long, OrderMainMaster> filter = new HashMap<>(orderMainMasters.size());
            for (OrderMainMaster item : orderMainMasters) {
                orderIds.add(item.orderId);
                filter.put(item.orderId, item);
            }

            List<InsOrderMasterCpic> insOrderMasterCpics = insOrderMasterCpicService.listByOrderIds(orderIds);
            for (InsOrderMasterCpic item : insOrderMasterCpics) {
                OrderMainMaster orderMainMaster = filter.get(item.getOrderId());
                if (orderMainMaster != null
                        && Objects.equals(orderMainMaster.getMasterId(), item.getMasterId())
                        && Objects.equals(InsOrderMasterCpic.FORM_STATUS_DONE, item.getFormStatus())) {
                    orderMainMaster.setInsuranceNo(item.getInsureNo());
                }
            }
        }

        private boolean sendMqMessage(OrderMainMaster orderMainMaster) {
            try {
                String mqMsgKey = String.format("sync_insMainMaster_%s", StringUtil.getRandomStringAndNumber3(13));
                OrderMainMasterMessage message = new OrderMainMasterMessage();
                message.setMqMsgKey(mqMsgKey);
                message.setData(orderMainMaster);
                String jsonContent = JSON.toJSONString(message);

                // 将师傅保单数据发送至消息队列
                zmnMQSender.send(
                        InsConsts.ZMN_TOPIC_ENGINEER,
                        InsConsts.MQ_TAG_ORDER_MAIN_MASTER ,
                        mqMsgKey,
                        jsonContent
                );
                log.info("【{}】send to MQ: content=[{}]", LOG_HEAD, jsonContent);
                return true;
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                return false;
            }
        }

        @Data
        private class OrderMainMasterMessage {
            private String mqMsgKey;
            private OrderMainMaster data;
        }

        @Data
        private class OrderMainMaster {
            private Long orderId;
            private Integer plat;
            private String insuranceNo;
            private Integer masterId;
        }
    }

    /**
     * 按单保险同步任务
     */
    @Slf4j
    public static class SyncInsOrderTask implements Runnable {
        private static final String LOG_HEAD = "按单保险同步任务";

        /**
         * 备份保险数据Service
         */
        private InsOrderSyncService insOrderSyncService;
        /**
         * 待同步保险数据
         */
        private List<InsOrderSync> insOrderSyncs;
        /**
         * RedisManager
         */
        private RedisManager redisManager;
        /**
         * 平台
         */
        private Integer platWork;

        @Override
        public void run() {
            if (_isSyncDisabled()) {
                return;
            }

            List<InsOrderSync> useableDatas = new LinkedList<>();
            List<Long> useableInsSyncIds = new LinkedList<>();
            List<Long> unUseableInsSyncIds = new LinkedList<>();

            insOrderSyncs.forEach(item -> {
                if (_validateInfo(item)) {
                    useableDatas.add(item);
                    useableInsSyncIds.add(item.getInsSyncId());
                }
                else {
                    if (item != null) {
                        unUseableInsSyncIds.add(item.getInsSyncId());
                    }
                }
            });

            boolean isZmnPlatWork = Objects.equals(GlobalConsts.PLAT_MARK_ZMN, platWork);
            String platTag = isZmnPlatWork ? "ZMN" : "YEYX";

            log.info("【{}】{}-同步任务开始：insSyncIds=[{}], unUseableInsSyncIds=[{}]", LOG_HEAD, platTag,
                    JSON.toJSONString(useableInsSyncIds), JSON.toJSONString(unUseableInsSyncIds));

            try {
                if (useableDatas.size() > 0) {
                    CpicInsSyncInvoker.ResponseData responseData = CpicInsSyncInvoker.syncData(useableDatas);
                    if (responseData.isSuccess()) {
                        // 更新同步标识
                        if (isZmnPlatWork) {
                            insOrderSyncService.updateZmnSyncedByKeys(useableInsSyncIds);
                        }
                        else {
                            insOrderSyncService.updateYeyxSyncedByKeys(useableInsSyncIds);
                        }
                    }
                }
            } catch (Exception e) {
                log.error(String.format("【%s】%s-同步失败：%s", LOG_HEAD, platTag, e.getMessage()), e);
            } finally {
                log.info("【{}】{}-同步任务结束：insSyncIds=[{}], unUseableInsSyncIds=[{}]", LOG_HEAD, platTag,
                        JSON.toJSONString(useableInsSyncIds), JSON.toJSONString(unUseableInsSyncIds));
            }
        }

        /**
         * 构造器
         * @param insOrderSyncService
         * @param insOrderSyncs
         * @param redisManager
         * @param platWork
         */
        public SyncInsOrderTask(InsOrderSyncService insOrderSyncService,
                                List<InsOrderSync> insOrderSyncs,
                                RedisManager redisManager,
                                Integer platWork) {
            this.insOrderSyncService = insOrderSyncService;
            this.insOrderSyncs = insOrderSyncs;
            this.redisManager = redisManager;
            this.platWork = platWork;
        }

        // 字符串处理，防止出现空指针
        private String _getString(String str) {
            return str == null ? "" : str;
        }

        /**
         * 校验信息完成性
         * @param insOrderSync
         * @return
         */
        private boolean _validateInfo(InsOrderSync insOrderSync) {
            if (insOrderSync == null
                    || StringUtil.isBlank(insOrderSync.getCode())
                    || insOrderSync.getType() == null
                    || insOrderSync.getStatus() == null
                    || insOrderSync.getTime() == null
                    || insOrderSync.getCreatedOn() == null) {
                return false;
            }

            // 师傅身份证号
            String servicemanCardNo = insOrderSync.getServicemanCardNo();

            if (StringUtil.isBlank(servicemanCardNo) && StringUtil.isBlank(insOrderSync.getServicemanName())) {
                // 师傅姓名和身份证号都不存在，返回false
                return false;
            }
            if (servicemanCardNo != null && servicemanCardNo.length() > 20) {
                // 师傅身份证号长度超过了20位，返回false
                return false;
            }

            return true;
        }

        /**
         * 同步功能是否未开启
         * @return
         */
        private boolean _isSyncDisabled() {
            if (redisManager != null) {
                return redisManager.exists(RedisKeyConsts.INS_DISABLE_SYNC_KEY);
            }

            return false;
        }
        /**
         * 关闭同步功能指定的时间
         * @param seconds 关闭的时间，单位：秒
         * @return
         */
        private void _disableSync(int seconds) {
            if (redisManager != null) {
                redisManager.setex(RedisKeyConsts.INS_DISABLE_SYNC_KEY, "true", Math.abs(seconds));
            }
        }

    }

    @Slf4j
    public static class SyncInsOrderMasterCpicTask implements Runnable {
        private static final String LOG_HEAD = "给工程师买保险任务";

        /**
         * 备份保险数据Service
         */
        private InsOrderMasterCpicService insOrderMasterCpicService;
        /**
         * 待同步保险数据
         */
        private List<InsOrderMasterCpic> insOrderMasterCpics;
        /**
         * RedisManager
         */
        private RedisManager redisManager;
        /**
         * 平台
         */
        private Integer platWork;

        @Override
        public void run() {
            if (_isSyncDisabled()) {
                return;
            }

            List<InsOrderMasterCpic> useableDatas = new LinkedList<>();
            List<Long> useableInsSyncIds = new LinkedList<>();
            List<Long> unUseableInsSyncIds = new LinkedList<>();

            insOrderMasterCpics.forEach(item -> {
                if (_validateInfo(item)) {
                    useableDatas.add(item);
                    useableInsSyncIds.add(item.getInsMasterId());
                }
                else {
                    if (item != null) {
                        unUseableInsSyncIds.add(item.getInsMasterId());
                    }
                }
            });

            boolean isZmnPlatWork = Objects.equals(GlobalConsts.PLAT_MARK_ZMN, platWork);
            String platTag = isZmnPlatWork ? "ZMN" : "YEYX";

            log.info("【{}】{}-买保险任务开始：insMasterCpicIds=[{}], unUseableInsMasterCpicIds=[{}]", LOG_HEAD, platTag,
                    JSON.toJSONString(useableInsSyncIds), JSON.toJSONString(unUseableInsSyncIds));

            try {
                if (useableDatas.size() > 0) {
                    CpicInsSyncInvoker.InsureResponse responseData = CpicInsSyncInvoker.syncInsureData(useableDatas);
                    if (responseData.isSuccess()) {
                        // 更新同步标识
                        insOrderMasterCpicService.updateRequestIdByKeys(useableDatas,
                                responseData.getData(), responseData.getInsStartDate(), responseData.getInsEndDate());
                    }
                }
            } catch (Exception e) {
                log.error(String.format("【%s】%s-同步失败：%s", LOG_HEAD, platTag, e.getMessage()), e);
            } finally {
                log.info("【{}】{}-买保险任务结束：insSyncIds=[{}], unUseableInsSyncIds=[{}]", LOG_HEAD, platTag,
                        JSON.toJSONString(useableInsSyncIds), JSON.toJSONString(unUseableInsSyncIds));
            }
        }

        /**
         * 构造器
         * @param insOrderMasterCpicService
         * @param insOrderMasterCpics
         * @param redisManager
         * @param platWork
         */
        public SyncInsOrderMasterCpicTask(InsOrderMasterCpicService insOrderMasterCpicService,
                                          List<InsOrderMasterCpic> insOrderMasterCpics,
                                          RedisManager redisManager,
                                          Integer platWork) {
            this.insOrderMasterCpicService = insOrderMasterCpicService;
            this.insOrderMasterCpics = insOrderMasterCpics;
            this.redisManager = redisManager;
            this.platWork = platWork;
        }

        // 字符串处理，防止出现空指针
        private String _getString(String str) {
            return str == null ? "" : str;
        }

        /**
         * 校验信息完成性
         * @param insOrderMasterCpic
         * @return
         */
        private boolean _validateInfo(InsOrderMasterCpic insOrderMasterCpic) {
            if (insOrderMasterCpic == null
                    || insOrderMasterCpic.getOrderId() == null
                    || StringUtil.isBlank(insOrderMasterCpic.getSchemaCode())
                    || StringUtil.isBlank(insOrderMasterCpic.getInsStartDate())
                    || StringUtil.isBlank(insOrderMasterCpic.getInsEndDate())) {
                return false;
            }

            // 师傅身份证号
            String masterCardNo = insOrderMasterCpic.getMasterCardNo();

            if (StringUtil.isBlank(masterCardNo) && StringUtil.isBlank(insOrderMasterCpic.getMasterName())) {
                // 师傅姓名和身份证号都不存在，返回false
                return false;
            }
            if (masterCardNo != null && masterCardNo.length() > 20) {
                // 师傅身份证号长度超过了20位，返回false
                return false;
            }

            return true;
        }

        /**
         * 同步功能是否未开启
         * @return
         */
        private boolean _isSyncDisabled() {
            if (redisManager != null) {
                return redisManager.exists(RedisKeyConsts.INS_DISABLE_SYNC_KEY);
            }

            return false;
        }
        /**
         * 关闭同步功能指定的时间
         * @param seconds 关闭的时间，单位：秒
         * @return
         */
        private void _disableSync(int seconds) {
            if (redisManager != null) {
                redisManager.setex(RedisKeyConsts.INS_DISABLE_SYNC_KEY, "true", Math.abs(seconds));
            }
        }
    }


    @Slf4j
    public static class QueryInsOrderMasterCpicTask implements Runnable {
        private static final String LOG_HEAD = "查询工程师保险出单任务";
        private static final long TIMEOUT_MILLIS = 5*60*1000; // 5分钟

        /**
         * 备份保险数据Service
         */
        private InsOrderMasterCpicService insOrderMasterCpicService;
        /**
         * 备份保险数据Service
         */
        private InsCpicInsureBService insCpicInsureBService;
        /**
         * 待查询保险数据
         */
        private List<InsOrderMasterCpic> insOrderMasterCpics;
        /**
         * RedisManager
         */
        private RedisManager redisManager;
        /**
         * 平台
         */
        private Integer platWork;

        @Override
        public void run() {
            if (_isSyncDisabled()) {
                return;
            }

            Map<String, InsOrderMasterCpic> finder = new HashMap<>(insOrderMasterCpics.size());
            Set<String> requestIdSet = new HashSet<>(insOrderMasterCpics.size());
            List<String> updatedCpicsIds = new LinkedList<>();
            long currTime = System.currentTimeMillis();
            insOrderMasterCpics.forEach(item -> {
                if (item.getRequestTime() == null || (currTime - item.getRequestTime().getTime()) < TIMEOUT_MILLIS) {
                    return; // 刚推送不超过5分钟的数据，不查询
                }

                if (StringUtil.isNotBlank(item.getRequestId())) {
                    requestIdSet.add(item.getRequestId());
                }
                finder.put(String.valueOf(item.getInsMasterId()), item);
            });
            List<String> requestIds = new ArrayList<>(requestIdSet);

            boolean isZmnPlatWork = Objects.equals(GlobalConsts.PLAT_MARK_ZMN, platWork);
            String platTag = isZmnPlatWork ? "ZMN" : "YEYX";

            log.info("【{}】{}-开始：requestIds=[{}]", LOG_HEAD, platTag, JSON.toJSONString(requestIds));
            try {
                for (String requestId : requestIds) {
                    CpicInsSyncInvoker.InsureResponse responseData = CpicInsSyncInvoker.queryInsureData(requestId);
                    if (!responseData.isSuccess() || StringUtil.isBlank(responseData.getData())) {
                        continue;
                    }

                    List<InsOrderMasterCpicDTO> cpicDTOS = JSON.parseArray(responseData.getData(), InsOrderMasterCpicDTO.class);
                    if (CollectionUtils.isEmpty(cpicDTOS)) {
                        continue;
                    }

                    for (InsOrderMasterCpicDTO item : cpicDTOS) {
                        if (item.getFormStatus() == null) {
                            continue;
                        }
                        int formStatus = item.getFormStatus().intValue();
                        if (formStatus != InsOrderMasterCpic.FORM_STATUS_FAIL
                                && formStatus != InsOrderMasterCpic.FORM_STATUS_DONE
                                && formStatus != InsOrderMasterCpic.FORM_STATUS_CANCELED) {
                            continue;
                        }
                        InsOrderMasterCpic dbInsOrderMasterCpic = finder.get(item.getExtAttr());
                        if (dbInsOrderMasterCpic != null) {
                            InsOrderMasterCpic model = new InsOrderMasterCpic();
                            model.setInsMasterId(dbInsOrderMasterCpic.getInsMasterId());
                            model.setFormStatus(item.getFormStatus());
                            if (StringUtil.isNotBlank(item.getInsureNo())) {
                                model.setInsureNo(item.getInsureNo());
                            }
                            if (StringUtil.isNotBlank(item.getMsg())) {
                                model.setMsg(item.getMsg());
                            }
                            updatedCpicsIds.add(item.getExtAttr());
                            insOrderMasterCpicService.updateByKey(model);
                        }
                    }
                }

                for (String item : updatedCpicsIds) {
                    finder.remove(item);
                }
                List<Long> insOrderMasterIds = finder.values().stream()
                        .map(InsOrderMasterCpic::getInsMasterId)
                        .collect(Collectors.toList());
                if (insOrderMasterIds != null && !insOrderMasterIds.isEmpty()) {
                    insOrderMasterCpicService.updateFormStatus2UnknowByKeys(insOrderMasterIds);
                }

            } catch (Exception e) {
                log.error(String.format("【%s】%s-同步失败：%s", LOG_HEAD, platTag, e.getMessage()), e);
            } finally {
                log.info("【{}】{}-结束：requestIds=[{}]", LOG_HEAD, platTag, JSON.toJSONString(requestIds));
            }
        }

        /**
         * 构造器
         * @param insOrderMasterCpicService
         * @param insOrderMasterCpics
         * @param redisManager
         * @param platWork
         */
        public QueryInsOrderMasterCpicTask(InsOrderMasterCpicService insOrderMasterCpicService,
                                           InsCpicInsureBService insCpicInsureBService,
                                           List<InsOrderMasterCpic> insOrderMasterCpics,
                                           RedisManager redisManager,
                                           Integer platWork) {
            this.insOrderMasterCpicService = insOrderMasterCpicService;
            this.insCpicInsureBService = insCpicInsureBService;
            this.insOrderMasterCpics = insOrderMasterCpics;
            this.redisManager = redisManager;
            this.platWork = platWork;
        }

        // 字符串处理，防止出现空指针
        private String _getString(String str) {
            return str == null ? "" : str;
        }

        /**
         * 校验信息完成性
         * @param insOrderMasterCpic
         * @return
         */
        private boolean _validateInfo(InsOrderMasterCpic insOrderMasterCpic) {
            if (insOrderMasterCpic == null
                    || insOrderMasterCpic.getOrderId() == null
                    || StringUtil.isBlank(insOrderMasterCpic.getSchemaCode())
                    || StringUtil.isBlank(insOrderMasterCpic.getInsStartDate())
                    || StringUtil.isBlank(insOrderMasterCpic.getInsEndDate())) {
                return false;
            }

            // 师傅身份证号
            String masterCardNo = insOrderMasterCpic.getMasterCardNo();

            if (StringUtil.isBlank(masterCardNo) && StringUtil.isBlank(insOrderMasterCpic.getMasterName())) {
                // 师傅姓名和身份证号都不存在，返回false
                return false;
            }
            if (masterCardNo != null && masterCardNo.length() > 20) {
                // 师傅身份证号长度超过了20位，返回false
                return false;
            }

            return true;
        }

        /**
         * 同步功能是否未开启
         * @return
         */
        private boolean _isSyncDisabled() {
            if (redisManager != null) {
                return redisManager.exists(RedisKeyConsts.INS_DISABLE_SYNC_KEY);
            }

            return false;
        }
        /**
         * 关闭同步功能指定的时间
         * @param seconds 关闭的时间，单位：秒
         * @return
         */
        private void _disableSync(int seconds) {
            if (redisManager != null) {
                redisManager.setex(RedisKeyConsts.INS_DISABLE_SYNC_KEY, "true", Math.abs(seconds));
            }
        }
    }

    @Slf4j
    public static class ReSyncInsOrderMasterCpicTask implements Runnable {
        private static final String LOG_HEAD = "给工程师买保险失败重试任务";
        private static final long FAILED_MILLIS = 10*60*1000; // 失败时间：10分钟
        private static final int INVALID_SECONDS = 15*60;    // 失效时间：15分钟

        /**
         * 备份保险数据Service
         */
        private InsOrderMasterCpicService insOrderMasterCpicService;
        /**
         * 待同步保险数据
         */
        private List<InsOrderMasterCpic> insOrderMasterCpics;
        /**
         * RedisManager
         */
        private RedisManager redisManager;
        /**
         * TaskManager
         */
        private TaskManager taskManager;
        /**
         * 平台
         */
        private Integer platWork;

        @Override
        public void run() {
            if (_isSyncDisabled()) {
                return;
            }

            List<InsOrderMasterCpic> useableDatas = new LinkedList<>();
            List<Long> reSyncInsMasterIds = new LinkedList<>();
            long currTime = System.currentTimeMillis();
            insOrderMasterCpics.forEach(item -> {
                if (item.getRequestTime() == null || (currTime - item.getRequestTime().getTime()) < FAILED_MILLIS) {
                    return; // 失败不足10分钟的数据，暂不重试
                }
                useableDatas.add(item);
                reSyncInsMasterIds.add(item.getInsMasterId());
            });

            boolean isZmnPlatWork = Objects.equals(GlobalConsts.PLAT_MARK_ZMN, platWork);
            String platTag = isZmnPlatWork ? "ZMN" : "YEYX";

            log.info("【{}】{}-买保险任务开始：insMasterCpicIds=[{}]", LOG_HEAD, platTag,
                    JSON.toJSONString(reSyncInsMasterIds));

            try {
                if (useableDatas.size() > 0) {
                    CpicInsSyncInvoker.InsureResponse responseData = CpicInsSyncInvoker.syncInsureData(useableDatas);
                    if (responseData.isSuccess()) {
                        // 更新同步标识
                        insOrderMasterCpicService.updateRequestIdByKeys(useableDatas,
                                responseData.getData(), responseData.getInsStartDate(), responseData.getInsEndDate());

                        addResyncResultCheckJob(reSyncInsMasterIds);
                    }
                }
            } catch (Exception e) {
                log.error(String.format("【%s】%s-同步失败：%s", LOG_HEAD, platTag, e.getMessage()), e);
            } finally {
                log.info("【{}】{}-买保险任务结束：insSyncIds=[{}]", LOG_HEAD, platTag,
                        JSON.toJSONString(reSyncInsMasterIds));
            }
        }

        /**
         * 构造器
         * @param insOrderMasterCpicService
         * @param insOrderMasterCpics
         * @param redisManager
         * @param platWork
         */
        public ReSyncInsOrderMasterCpicTask(InsOrderMasterCpicService insOrderMasterCpicService,
                                            List<InsOrderMasterCpic> insOrderMasterCpics,
                                            RedisManager redisManager,
                                            TaskManager taskManager,
                                            Integer platWork) {
            this.insOrderMasterCpicService = insOrderMasterCpicService;
            this.insOrderMasterCpics = insOrderMasterCpics;
            this.redisManager = redisManager;
            this.taskManager = taskManager;
            this.platWork = platWork;
        }

        // 字符串处理，防止出现空指针
        private String _getString(String str) {
            return str == null ? "" : str;
        }

        /**
         * 校验信息完成性
         * @param insOrderMasterCpic
         * @return
         */
        private boolean _validateInfo(InsOrderMasterCpic insOrderMasterCpic) {
            if (insOrderMasterCpic == null
                    || insOrderMasterCpic.getOrderId() == null
                    || StringUtil.isBlank(insOrderMasterCpic.getSchemaCode())
                    || StringUtil.isBlank(insOrderMasterCpic.getInsStartDate())
                    || StringUtil.isBlank(insOrderMasterCpic.getInsEndDate())) {
                return false;
            }

            // 师傅身份证号
            String masterCardNo = insOrderMasterCpic.getMasterCardNo();

            if (StringUtil.isBlank(masterCardNo) && StringUtil.isBlank(insOrderMasterCpic.getMasterName())) {
                // 师傅姓名和身份证号都不存在，返回false
                return false;
            }
            if (masterCardNo != null && masterCardNo.length() > 20) {
                // 师傅身份证号长度超过了20位，返回false
                return false;
            }

            return true;
        }

        /**
         * 添加提示任务
         * @param reSyncInsMasterIds
         */
        private void addResyncResultCheckJob(List<Long> reSyncInsMasterIds) {
            if (reSyncInsMasterIds == null || reSyncInsMasterIds.isEmpty()) {
                return;
            }
            StringBuilder idsBuilder = new StringBuilder();
            for (Long item : reSyncInsMasterIds) {
                idsBuilder.append(",").append(String.valueOf(item));
            }

            Date triggerDate = DateUtil.getNowDeferMinutes(5);// 5分钟后执行

            Job job = new Job();
            job.setTaskId(String.format("%s:%d",
                    TaskConsts.TASK_ID_RESYNC_INS_ORDER_CHECK,
                    DateUtil.toString(triggerDate, DateUtil.FORMAT_DEFAULT)
            ));
            job.setParam(TaskManager.SHARD_FIELD, TaskConsts.TASK_ID_RESYNC_INS_ORDER_CHECK);
            job.setParam("insMasterIds", idsBuilder.substring(1));
            job.setTriggerDate(triggerDate); // 5分钟后执行

            taskManager.submitTask2(job);
        }

        /**
         * 同步功能是否未开启
         * @return
         */
        private boolean _isSyncDisabled() {
            if (redisManager != null) {
                return redisManager.exists(RedisKeyConsts.INS_DISABLE_SYNC_KEY);
            }

            return false;
        }
        /**
         * 关闭同步功能指定的时间
         * @param seconds 关闭的时间，单位：秒
         * @return
         */
        private void _disableSync(int seconds) {
            if (redisManager != null) {
                redisManager.setex(RedisKeyConsts.INS_DISABLE_SYNC_KEY, "true", Math.abs(seconds));
            }
        }
    }
}
